#include "dap_main.h"
#include "DAP_config.h"
#include "DAP.h"
#include "usb_public.h"
#include "usbd_core.h"
#include "esp_log.h"
#include "freertos/ringbuf.h"
// LwIP网络栈
#include "lwip/err.h"     // LWIP错误处理头文件
#include "lwip/sockets.h" // LWIP套接字头文件
#include "lwip/sys.h"     // LWIP系统头文件
#include <lwip/netdb.h>   // LWIP网络数据库头文件

// 相关头文件包含
// 引入usbip服务器相关的头文件，用于处理USBIP协议相关的操作
#include "usbip_server.h"
#include "usbip_defs.h"
// 引入WiFi配置的头文件，可能用于处理与WiFi连接相关的配置
#include "wifi_configuration.h"
                                                                                        static const char *TAG = "dap_main";
//dap任务的CPU亲和性
#define DAP_TASK_AFFINITY 1

// 静态全局变量
// 定义处理后的DAP数据变量，用于存储处理后的DAP数据包
static char DAPDataProcessed[DAP_PACKET_SIZE];
// 定义DAP响应计数器，用于记录DAP响应的次数
volatile int dap_respond = 0;

// 定义DAP处理重启标志，初始值为无信号
reset_handle_t kRestartDAPHandle = NO_SIGNAL;

//定义了DAP配置结构体
DAP_config_t g_DAP_config;

/**
 * @brief 分配DAP环形缓冲区
 * 该函数用于创建输入和输出的环形缓冲区，用于DAP数据的存储和传输。
 * 在创建缓冲区之前，会先获取数据响应互斥量，确保操作的线程安全。
 */
void malloc_dap_ringbuf()
{
        ESP_LOGE(TAG, "malloc DAP ringbuf/mux");
    // 检查数据响应互斥量是否存在，并尝试获取该互斥量
    if (g_DAP_config.data_response_mux && xSemaphoreTake(g_DAP_config.data_response_mux, portMAX_DELAY) == pdTRUE) {
        // 如果输入缓冲区句柄为空，则创建输入缓冲区
        if (g_DAP_config.dap_dataIN_handle == NULL) {
            // 创建一个大小为DAP_HANDLE_SIZE * DAP_BUFFER_NUM的字节类型环形缓冲区
            g_DAP_config.dap_dataIN_handle = xRingbufferCreate(DAP_BUFFER_SIZE, RINGBUF_TYPE_NOSPLIT);
        }
        // 如果输出缓冲区句柄为空，则创建输出缓冲区
        if (g_DAP_config.dap_dataOUT_handle == NULL) {
            // 创建一个大小为DAP_HANDLE_SIZE * DAP_BUFFER_NUM的字节类型环形缓冲区
            g_DAP_config.dap_dataOUT_handle = xRingbufferCreate(DAP_BUFFER_SIZE, RINGBUF_TYPE_NOSPLIT);
        }
        // 释放数据响应互斥量
        xSemaphoreGive(g_DAP_config.data_response_mux);
    }
}

/**
 * @brief 释放DAP环形缓冲区
 * 该函数用于删除输入和输出的环形缓冲区，释放相关资源。
 * 在删除缓冲区之前，会先获取数据响应互斥量，确保操作的线程安全。
 */
void free_dap_ringbuf()
{
    ESP_LOGE(TAG, "Free DAP ringbuf/mux");
    // 检查数据响应互斥量是否存在，并尝试获取该互斥量
    if (g_DAP_config.data_response_mux && xSemaphoreTake(g_DAP_config.data_response_mux, portMAX_DELAY) == pdTRUE) {
        // 如果输入缓冲区句柄存在，则删除输入缓冲区
        if (g_DAP_config.dap_dataIN_handle) {
            vRingbufferDelete(g_DAP_config.dap_dataIN_handle);
        }
        // 如果输出缓冲区句柄存在，则删除输出缓冲区
        if (g_DAP_config.dap_dataOUT_handle) {
            vRingbufferDelete(g_DAP_config.dap_dataOUT_handle);
        }
        // 将输入和输出缓冲区句柄置为NULL
        g_DAP_config.dap_dataIN_handle = g_DAP_config.dap_dataOUT_handle = NULL;
        // 释放数据响应互斥量
        xSemaphoreGive(g_DAP_config.data_response_mux);
    }
}

/**
 * @brief DAP处理线程
 * @param argument 线程参数(未使用)
 * 该函数是DAP处理的主线程，负责初始化环形缓冲区和互斥量，处理DAP数据请求，以及重启DAP处理。
 */
void DAP_Thread(void *argument)
{
    // 定义数据包大小变量
    size_t packetSize;
    // 定义响应长度变量
    int resLength;
    // 定义DAP数据包指针
    char *item_buf;

    // 无限循环，持续处理DAP数据
    for (;;) {
        while (1) {
            // 检查是否需要重启DAP处理
            if (kRestartDAPHandle) {
                // 先释放现有资源
                free_dap_ringbuf();

                // 如果重启标志为重置句柄
                if (kRestartDAPHandle == RESET_HANDLE) {
                    // 重新分配资源
                    malloc_dap_ringbuf();
                    // 检查重新分配是否成功
                    if (g_DAP_config.dap_dataIN_handle == NULL || g_DAP_config.dap_dataOUT_handle == NULL) {
                        // 分配失败，打印错误信息
                        ESP_LOGE(TAG, "Can not create DAP ringbuf/mux!");
                        // 删除当前任务
                        vTaskDelete(NULL);
                    }
                }
                // 重置标志
                kRestartDAPHandle = NO_SIGNAL;
            }

            // 等待任务通知
            ulTaskNotifyTake(pdFALSE, portMAX_DELAY);

            // 检查缓冲区是否有效
            if (g_DAP_config.dap_dataIN_handle == NULL || g_DAP_config.dap_dataOUT_handle == NULL) {
                // 可能正在使用其他链接，等待...
                continue;
            }

            // 从输入环形缓冲区获取数据
            packetSize = 0;
            item_buf = (char *)xRingbufferReceive(g_DAP_config.dap_dataIN_handle, &packetSize,
                                                  pdMS_TO_TICKS(2));
            /*  实际数据的大小不定，数据存有大小，但是写进环形缓冲区固定为 DAP_HANDLE_SIZE */
            if (packetSize == 0) {
                // 无数据可处理，跳出循环
                break;
            }

            // 处理特殊命令ID
            if (item_buf[0] == ID_DAP_QueueCommands) {
                // 将队列命令转换为执行命令
                item_buf[0] = ID_DAP_ExecuteCommands;
            }

            // 处理DAP命令
            resLength = DAP_ProcessCommand((uint8_t *)item_buf, (uint8_t *)DAPDataProcessed);
            // 确保长度在16位范围内
            resLength &= 0xFFFF;

            // 处理完成，释放缓冲区
            vRingbufferReturnItem(g_DAP_config.dap_dataIN_handle, item_buf);

            // 准备回复数据

            // 将处理后的数据放入输出环形缓冲区
            xRingbufferSend(g_DAP_config.dap_dataOUT_handle, (void *)DAPDataProcessed, resLength, portMAX_DELAY);
            //ESP_LOGI(TAG, "data_response_mux :%d", g_DAP_config.data_response_mux);
            // 更新响应计数器
            if (xSemaphoreTake(g_DAP_config.data_response_mux, portMAX_DELAY) == pdTRUE) {
                // 响应计数器加1
                ++dap_respond;
                // 释放数据响应互斥量
                xSemaphoreGive(g_DAP_config.data_response_mux);
            }
        }
    }
}

pDAP_config_t DAP_Pubilc_Init(void)
{
    //ESP_EARLY_LOGI(TAG, "DAP_Pubilc_Init");
    // 初始化环形缓冲区和互斥量
    // 创建输入环形缓冲区
    g_DAP_config.dap_dataIN_handle = xRingbufferCreate(DAP_BUFFER_SIZE, RINGBUF_TYPE_NOSPLIT);
    // 创建输出环形缓冲区
    g_DAP_config.dap_dataOUT_handle = xRingbufferCreate(DAP_BUFFER_SIZE, RINGBUF_TYPE_NOSPLIT);
    // 创建数据响应互斥量
    g_DAP_config.data_response_mux = xSemaphoreCreateMutex();
    //ESP_LOGI(TAG, "data_response_mux :%d", g_DAP_config.data_response_mux);

    kRestartDAPHandle = NO_SIGNAL;

    // DAP handle task
    xTaskCreatePinnedToCore(DAP_Thread, "DAP_Task", 3 * 1024, NULL, 10, &g_DAP_config.kDAPTaskHandle,
                            DAP_TASK_AFFINITY);
    return &g_DAP_config;
}

void DAP_Pubilc_Deinit(pDAP_config_t pDAP_config)
{
    free_dap_ringbuf();
    kRestartDAPHandle = DELETE_HANDLE;
    vSemaphoreDelete(pDAP_config->data_response_mux);
    vTaskDelete(pDAP_config->kDAPTaskHandle);
}
/***********************************************************usbip************************************************************************************/

/**
 * @brief 处理DAP数据请求
 * @param header USBIP阶段2头部指针，指向USBIP阶段2的头部信息
 * @param length 数据长度，即接收到的DAP数据的长度
 * 该函数用于处理接收到的DAP数据请求，将数据放入输入环形缓冲区，并通知DAP任务进行处理。
 */
void handle_dap_data_request(usbip_stage2_header *header, uint32_t length)
{
    // 将指针指向URB数据包开始位置
    uint8_t *data_in = (uint8_t *)header;
    data_in = &(data_in[sizeof(usbip_stage2_header)]);

    // 如果启用了WinUSB模式
#if (USE_WINUSB == 1)
    // 发送阶段2提交数据的快速响应，不携带数据
    send_stage2_submit_data_fast(header, NULL, 0);
    // 将数据放入输入环形缓冲区，发送固定大小的缓冲区，忽略输入包大小
    xRingbufferSend(g_DAP_config.dap_dataIN_handle, data_in , length, portMAX_DELAY);
#else
    // 普通模式处理
    // 发送阶段2提交数据的快速响应，不携带数据
    send_stage2_submit_data_fast(header, NULL, 0);
    // 将数据放入输入环形缓冲区
    xRingbufferSend(dap_dataIN_handle, data_in, DAP_HANDLE_SIZE, portMAX_DELAY);
#endif

    // 通知DAP任务处理数据
    xTaskNotifyGive(g_DAP_config.kDAPTaskHandle);
}

/**
 * @brief 快速回复处理
 * @param buf 数据缓冲区，指向待处理的数据缓冲区
 * @param length 数据长度，即待处理的数据的长度
 * @param dap_req_num DAP请求数量，即当前待处理的DAP请求的数量
 * @return 处理成功返回1，否则返回0
 * 该函数用于快速处理DAP响应，根据DAP请求数量发送相应的响应数据。
 */
int fast_reply(uint8_t *buf, uint32_t length, int dap_req_num)
{
    // 将缓冲区指针转换为USBIP阶段2头部指针
    usbip_stage2_header *buf_header = (usbip_stage2_header *)buf;

    // 如果有DAP请求需要处理
    if (dap_req_num > 0) {
        // 定义DAP数据包指针
        char *item;
        // 定义数据包大小变量
        size_t packetSize = 0;
        // 从输出环形缓冲区获取数据
        item = (char *)xRingbufferReceiveUpTo(g_DAP_config.dap_dataOUT_handle, &packetSize,
                                              portMAX_DELAY, DAP_HANDLE_SIZE);
        // 如果获取到的数据大小等于DAP处理单元大小
        if (packetSize == DAP_HANDLE_SIZE) {
            // 发送响应数据
            // 如果启用了WinUSB模式
#if (USE_WINUSB == 1)
            // 发送阶段2提交数据的快速响应，携带处理后的数据
            send_stage2_submit_data_fast((usbip_stage2_header *)buf, item, packetSize);
#else
            // 发送阶段2提交数据的快速响应，携带固定大小的处理后的数据
            send_stage2_submit_data_fast((usbip_stage2_header *)buf, item->buf, DAP_HANDLE_SIZE);
#endif

            // 更新响应计数器
            if (xSemaphoreTake(g_DAP_config.data_response_mux, portMAX_DELAY) == pdTRUE) {
                // 响应计数器减1
                --dap_respond;
                // 释放数据响应互斥量
                xSemaphoreGive(g_DAP_config.data_response_mux);
            }

            // 返还缓冲区
            vRingbufferReturnItem(g_DAP_config.dap_dataOUT_handle, (void *)item);
            // 处理成功，返回1
            return 1;
        } else if (packetSize > 0) {
            // 输出数据包大小错误，打印错误信息
            os_printf("输出数据包大小错误:%d!\r\n", packetSize);
        }
    } else {
        // 无DAP请求，发送空响应
        // 设置USBIP阶段2头部的命令为响应提交
        buf_header->base.command = PP_HTONL(USBIP_STAGE2_RSP_SUBMIT);
        // 设置USBIP阶段2头部的方向为输出
        buf_header->base.direction = PP_HTONL(USBIP_DIR_OUT);
        // 设置USBIP阶段2头部的状态为0
        buf_header->u.ret_submit.status = 0;
        // 设置USBIP阶段2头部的数据长度为0
        buf_header->u.ret_submit.data_length = 0;
        // 设置USBIP阶段2头部的错误计数为0
        buf_header->u.ret_submit.error_count = 0;
        // 通过网络发送数据
        usbip_network_send(kSock, buf, 48, 0);
        // 处理成功，返回1
        return 1;
    }

    // 处理失败，返回0
    return 0;
}

/**
 * @brief 处理DAP unlink请求
 * 该函数用于处理DAP unlink请求，清理可能存在的未返回数据，避免滞后响应。
 */
void handle_dap_unlink()
{
    // USBIP_CMD_UNLINK表示调用usb_unlink_urb()或usb_kill_urb()
    // 此函数用于清理可能存在的未返回数据，避免滞后响应

    // 如果有未完成的响应
    if (dap_respond > 0) {
        // 定义DAP数据包指针
        char *item;
        // 定义数据包大小变量
        size_t packetSize = 0;
        // 从输出环形缓冲区获取数据
        item = (char *)xRingbufferReceiveUpTo(g_DAP_config.dap_dataOUT_handle, &packetSize,
                                              pdMS_TO_TICKS(10), DAP_HANDLE_SIZE);
        // 如果获取到的数据大小等于DAP处理单元大小
        if (packetSize == DAP_HANDLE_SIZE) {
            // 清理未返回的数据
            if (xSemaphoreTake(g_DAP_config.data_response_mux, portMAX_DELAY) == pdTRUE) {
                // 响应计数器减1
                --dap_respond;
                // 释放数据响应互斥量
                xSemaphoreGive(g_DAP_config.data_response_mux);
            }
            // 返还缓冲区
            vRingbufferReturnItem(g_DAP_config.dap_dataOUT_handle, (void *)item);
        }
    }
}